#pragma once

#include <d3d12.h>
#include "Selah.h"

using namespace SL;
struct Texture
{
    ID3D12Resource* pResource = nullptr;
    D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle;
    D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle;
};
class CalculationApp
{
public:
public:
    CalculationApp() = default;
    void run();
    void onInitialize() {}
    void onLoad() {}           // assets resources
    void onUpdate(float dt) {} // animation
    void onFixedUpdate() {}    // physics, AI, etc
    void onShutdown() {}

    ~CalculationApp() = default;

private:
    void initialize();
    bool initializeBackend();
    void shutDown();
    void shutDownBackend();
    bool initialized{false};

    void createResouces();
    void calculate();
    void getResults();

protected:
    ExampleDescriptorHeapAllocator srvDescHeapAlloc;
    ExampleDescriptorHeapAllocator rtvDescHeapAlloc;

    // Config for example app
    // frames in flight == back buffers, for simplicity
    static const int APP_NUM_FRAMES_IN_FLIGHT = 2;
    static const int APP_NUM_BACK_BUFFERS = 2;
    static const int APP_SRV_HEAP_SIZE = 64;

    UINT frameIndex = 0;
    void* constantData;

    ID3D12Device* device = nullptr;
    ID3D12DescriptorHeap* rtvDescHeap = nullptr;
    ID3D12DescriptorHeap* srvDescHeap = nullptr;
    ID3D12CommandQueue* directQueue = nullptr;
    ID3D12CommandQueue* copyQueue = nullptr;
    ID3D12CommandAllocator* cmdAllocDirect = nullptr;
    ID3D12CommandAllocator* cmdAllocCopy = nullptr;
    ID3D12GraphicsCommandList* cmdListDirect = nullptr;
    ID3D12GraphicsCommandList* cmdListCopy = nullptr;
    ID3D12Fence* fence = nullptr;
    HANDLE fenceEvent = nullptr;

    Texture inputTexture{};
    Texture outputTexture{};
    Texture readbackTexture{};
    ID3D12Resource* uploadBuffer = nullptr;
    ID3D12RootSignature* rootSig;
    ID3D12PipelineState* pso;

    std::vector<ID3D12Object*> gpu_objects;

    int width, height, channels;
    UINT rt_width, rt_height;
    void waitForGpu();
    void moveToNextFrame();
    UINT fenceValues;
    void uploadResourceTexture(
        UINT width,
        UINT height,
        ID3D12Resource** ppResource,
        D3D12_RESOURCE_STATES afterState,
        UINT NumSubresources,
        const D3D12_SUBRESOURCE_DATA* pSrcData
    );
    void uploadResourceHDR(
        UINT width,
        UINT height,
        ID3D12Resource** ppResource,
        D3D12_RESOURCE_STATES afterState,
        UINT NumSubresources,
        const D3D12_SUBRESOURCE_DATA* pSrcData
    );

};
